﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace IEx
{
    public delegate void EnQueueDelegate(int queueCount);
    public delegate void DeQueueDelegate(int queueCount);

    public abstract class Queue<T> where T : class
    {
        protected List<T> itemsQueue = new List<T>();

        public EnQueueDelegate OnEnqueue
        {
            get;
            set;
        }

        public DeQueueDelegate DeEnqueue
        {
            get;
            set;
        }

        public virtual void Enqueue(T item)
        {
            lock (this)
            {
                itemsQueue.Add(item);
                if (this.OnEnqueue != null)
                {
                    OnEnqueue.Invoke(this.QueueCount);
                }
            }
        }

        public virtual T Dequeue()
        {
            lock (this)
            {
                if (this.QueueCount > 0)
                {
                    T item = itemsQueue[0];
                    itemsQueue.RemoveAt(0);
                    if (this.DeEnqueue != null)
                    {
                        DeEnqueue.Invoke(this.QueueCount);
                    }
                    return item;
                }
                return default(T);
            }
        }

        public abstract bool Contains(T item);

        public virtual bool Any(Func<T, bool> predicate)
        {
            lock (this)
            {
                return predicate != null ? this.itemsQueue.Any(item => predicate(item)) : false;
            }
        }

        public void ClearQueue()
        {
            lock (this)
            {
                this.itemsQueue.Clear();
            }
        }

        public int QueueCount
        {
            get
            {
                lock (this)
                {
                    return this.itemsQueue.Count;
                }
            }
        }
    }
}
